<?php
//import enums
require_once ("../enums/enums.php");

//import DO
require_once ("../persistance/data/ResponsableDO.php");
require_once ("../persistance/data/CommandeFactureDO.php");
require_once ("../persistance/data/LieuDO.php");
require_once ("../persistance/data/DetailDO.php");
require_once ("../persistance/data/TypeArticleDO.php");
require_once ("../persistance/data/ArticleDO.php");

//import DAO
require_once ("../persistance/dao/ResponsableDAO.php");
require_once ("../persistance/dao/CommandeFactureDAO.php");
require_once ("../persistance/dao/LieuDAO.php");
require_once ("../persistance/dao/DetailDAO.php");
require_once ("../persistance/dao/TypeArticleDAO.php");
require_once ("../persistance/dao/ArticleDAO.php");

//import Bean data
require_once ("../bean/data/Commande.php");
require_once ("../bean/data/Utilisateur.php");
require_once ("../bean/data/Lieu.php");
require_once ("../bean/data/Facture.php");
require_once ("../bean/data/Article.php");

/**
 *	Service disponnible a tout client
 *
 * @author Quentin Laujac, Charles Hurtevent
 *
 */
class ClientService {

	private $commandeDAO;
	private $responsableDAO;
	private $lieuDAO;
	private $detailDAO;
	private $typeArticleDAO;
	private $articleDAO;


	public function __construct() {
		$this->commandeDAO = new CommandeFactureDAO();
		$this->responsableDAO = new ResponsableDAO();
		$this->lieuDAO = new LieuDAO();
		$this->detailDAO = new DetailDAO();
		$this->typeArticleDAO = new TypeArticleDAO();
		$this->articleDAO = new ArticleDAO();
	}




	//------------------------------------------------------SERVICES--------------------------------------------------------------------------

	/**
	 *	Annule la commande si elle n'a pas ete valide
	 *
	 * @param Commande $commande
	 */
	public function annulerCommande(Commande $commande){
		if($commande->isValide()){
			return ANNULATION_COMMANDE_IMPOSSIBLE;
		}
		$commandeFactureDO = $this->convertCommandeToCommandeFactureDO($commande);
		$listDetailDO = $this->convertListArticleToListDetailDO($commande->getListArticle(), $commande->getNumeroCommande());
		$this->detailDAO->deleteListDetailDO($listDetailDO);
		$this->commandeDAO->deleteCommandeFactureDO($commandeFactureDO);

		return null;
	}

	/**
	 * retourn la liste des lieu connu de la base par ordre croissant
	 */
	public function getListLieuConnu(){
		$listLieu = new ArrayObject();
		$listLieuDO = $this->lieuDAO->getListLieuDO();

		foreach ( $listLieuDO as $lieuDO ) {
			$listLieu->append ( $this->convertLieuDOtoLieu ( $lieuDO ) );

		}
		return $listLieu;

	}

	/**
	 * retourne une liste de commande correspondant a l'historique du client
	 */
	public function getHistoriqueCommande(Utilisateur $client) {
		$listCommandeDO = $this->commandeDAO->getListCommandeFactureDOByNumResponsable ( $client->getNumeroResponsable() );
		if ($listCommandeDO == null) {
			return null;
		}

		$listcommande = new ArrayObject ();

		foreach ( $listCommandeDO as $commandeFactureDO ) {
			$numCommande = $commandeFactureDO->getNumeroCommande();
			$lieuDO = $this->getLieuDO($commandeFactureDO);
			$lieu = new Lieu();
			$lieu->setAdresse($lieuDO->getAdresse());
			$lieu->setNumeroLieu($lieuDO->getNumeroLieu());
			$listArticle = $this->getListArticleBynumCommande($numCommande);
			$commande = $this->convertCommandeFactureDOtoCommande ( $commandeFactureDO, $lieu, $client, $listArticle);
			$listcommande->append ($commande);
		}
		return $listcommande;
	}

	/**
	 *
	 * Enregistre une commande dans la base
	 * @param Commande $commande
	 */
	public function enregistrerCommande(Commande $commande) {
		//Verification de la commande
		$messageErreur = $this->commandeAValider($commande);
		if($messageErreur != null){
			return $messageErreur;
		}

		if($this->getNombreCommandeNonValide($commande->getClient()) > 5){
			return TROP_DE_COMMANDE_NON_VALIDE;
		}

		//la commande peut etre enregistre
		$commande->setNumeroCommande($this->getDernierNumeroCommande() + 1);
		$commandeFactureDO = $this->convertCommandeToCommandeFactureDO($commande);
		$listDetailDO = $this->convertListArticleToListDetailDO($commande->getListArticle(), $commande->getNumeroCommande());
		$listDetailDO = $this->purgeListDetailDO($listDetailDO);
		$this->commandeDAO->insertCommandeFactureDO($commandeFactureDO);
		$this->detailDAO->insertListDetailDO($listDetailDO);
		$this->miseAJourQuantiteArticleDisponible($commande);

		return null;
	}

	/**
	 *
	 * Met a jour la commande
	 * @param Commande $commande
	 */
	public function miseAJourCommande(Commande $commande) {
		//Verification de la commande
		$messageErreur = $this->commandeAValider($commande);
		if($messageErreur != null){
			return $messageErreur;
		}

		//la commande peut etre mise a jour
		$commandeFactureDO = $this->convertCommandeToCommandeFactureDO($commande);
		$listDetailDO = $this->convertListArticleToListDetailDO($commande->getListArticle(), $commande->getNumeroCommande());
		$this->detailDAO->deleteListDetailDO($listDetailDO);
		$listDetailDO = $this->purgeListDetailDO($listDetailDO);
		$this->detailDAO->insertListDetailDO($listDetailDO);
		$this->commandeDAO->updateCommandeFactureDO($commandeFactureDO);
		$this->miseAJourQuantiteArticleDisponible($commande);

		return null;
	}


	/**
	 * Retourne la liste des articles correspondant au numero de commande
	 * @param entier $numCommande
	 */
	public function getListArticleBynumCommande($numCommande){
		$listDetailDO = $this->detailDAO->getListDetailDOByNumCommande($numCommande);
		$listArticle = new ArrayObject();
		foreach ( $listDetailDO as $detailDO ) {
			$articleDO = $this->getArticleDOByDetailDO($detailDO);
			$typeArticleDO = $this->typeArticleDAO->getTypeArticleDOByCodeTypeArticle($articleDO->getCodeTypeArticle());
			$article = $this->convertDetailDOtoArticle($detailDO, $articleDO, $typeArticleDO);
			$listArticle->append($article);
		}

		return $listArticle;
	}


	/**
	 * Retourne tout les articles present dans la base
	 */
	public function getListArticle(){
		$listArticleDO = $this->articleDAO->getListArticleDO();
		$listArticle = new ArrayObject();
		foreach ( $listArticleDO as $articleDO ) {
			$typeArticleDO = $this->typeArticleDAO->getTypeArticleDOByCodeTypeArticle($articleDO->getCodeTypeArticle());
			$article = $this->convertDetailDOtoArticle(new DetailDO(), $articleDO, $typeArticleDO);
			$listArticle->append ($article);
		}
		return $listArticle;
	}






	//--------------------------------------------VERIFICATION COMMANDES-----------------------------------------

	private function commandeAValider($commande){
		if (!$this->isQuantiteNumber($commande)){
			return QUANTITE_NON_NUMERIC;
		}

		if($this->isQuantiteNegative($commande)){
			return QUANTITE_NEGATIVE;
		}

		if($this->isCommandeVide($commande)){
			return COMMANDE_VIDE;
		}

		if($this->isAplusDeSixArticleDifferent($commande)){
			return COMMANDE_PLUS_SIX_ARTICLE;
		}

		if(!$this->isResteSuffisammentStock($commande)){
			return PAS_ASSEZ_DE_STOCK;
		}

		return null;
	}

	private function isQuantiteNegative(Commande $commande){
		foreach($commande->getListArticle() as $article){
			if($article->getQuantiteCommandee() < 0){
				return true;
			}
		}
		return false;
	}

	private function isQuantiteNumber($commande){
		foreach($commande->getListArticle() as $article){
			if(!is_numeric($article->getQuantiteCommandee()) || is_float($article->getQuantiteCommandee() * 1)){
				return false;
			}
		}
		return true;
	}

	private function isResteSuffisammentStock(Commande $commande){
		foreach($commande->getListArticle() as $article){
			if($article->getQuantiteDisponible() < $article->getQuantiteCommandee()){
				return false;
			}
		}
		return true;
	}

	private function getNombreCommandeNonValide(Utilisateur $client){
		$listCommandeDO = $this->commandeDAO->getListCommandeFactureDOByNumResponsable($client->getNumeroResponsable());
		$nombreCommandeNonValide = 0;
		foreach($listCommandeDO as $commandeDO){

			if(!$commandeDO->estTerminee()){
				$nombreCommandeNonValide++;
			}
		}
		return $nombreCommandeNonValide;
	}

	private function isCommandeVide(Commande $commande){
		if($commande->getListArticle() == null){
			return true;
		}
		foreach ($commande->getListArticle() as $article){
			if($article->getQuantiteCommandee() > 0){
				return false;
			}
		}
		return true;
	}

	private function isAplusDeSixArticleDifferent(Commande $commande){
		$quantiteArticleDifferent = 0;
		foreach ($commande->getListArticle() as $article){
			if($article->getQuantiteCommandee() > 0){
				$quantiteArticleDifferent++;
			}
			if($quantiteArticleDifferent > 6){
				return true;
			}
		}
		return false;
	}





	//------------------------GETTER private-------------------------------------------------------------
	private function getDernierNumeroCommande(){
		return $this->commandeDAO->getDernierNumCommande();
	}

	private function getArticleDOByDetailDO(DetailDO $detailDO){
		return $this->articleDAO->getArticleDO($detailDO->getNumeroArticle());
	}

	private function getListLieu(ResponsableDO $responsableDO){
		$listLieu = new ArrayObject();
		$listLieuDO = $this->lieuDAO->getListLieuDOByNumStructure($responsableDO->getNumeroStructure());

		foreach ( $listLieuDO as $lieuDO ) {
			$listLieu->append ( $this->convertLieuDOtoLieu ( $lieuDO ) );

		}
		return $listLieu;

	}

	private function getLieuDO(CommandeFactureDO $commandeFactureDO){
		$lieuDO = $this->lieuDAO->getLieuDOByNumLieu($commandeFactureDO->getNumeroLieu());

		return $this->convertLieuDOtoLieu($lieuDO);
	}



	//-----------------------SERVICE PRIVE------------------------------------------------------------------
	private function miseAJourQuantiteArticleDisponible(Commande $commande){
		if($commande->isValide()){
			foreach ($commande->getListArticle() as $article){
				$article->setQuantiteDisponible($article->getQuantiteDisponible() - $article->getQuantiteCommandee());
				$articleDO = $this->convertArticleToArticleDO($article);
				$this->articleDAO->updateQuantiteDisponibleArticleDO($articleDO);
			}
		}
	}




	//-----------------------CONVERTION-----------------------------------------------------------------------
	/**
	 * retire de la listDetailDO tout les detailsDO ayant une quantite egale a 0
	 * @param ArrayObject $listDetailDO
	 */
	private function purgeListDetailDO(ArrayObject $listDetailDO){
		$listDetailDOPurge = new ArrayObject();
		foreach ($listDetailDO as $detailDO){
			if($detailDO->getQuantiteCommande() > 0){
				$listDetailDOPurge->append($detailDO);
			}
		}

		return $listDetailDOPurge;
	}

	private function convertCommandeToCommandeFactureDO(Commande $commande){
		$commandeFactureDO = new CommandeFactureDO();
		$commandeFactureDO->setDateCommande($commande->getDateCommande());
		$commandeFactureDO->setDateFacture($commande->getFacture()->getDateFacture());
		$commandeFactureDO->setEstColisFait($commande->isColisFait());
		$commandeFactureDO->setEstPaye(false);
		$commandeFactureDO->setEstTerminee($commande->isValide());
		$commandeFactureDO->setMontantFacture($commande->getFacture()->getMontantFacture());
		$commandeFactureDO->setNumeroCommande($commande->getNumeroCommande());
		$commandeFactureDO->setNumeroLieu($commande->getLieuLivraison()->getNumeroLieu());
		$commandeFactureDO->setNumeroResponsable($commande->getClient()->getNumeroResponsable());

		return $commandeFactureDO;
	}

	private function convertListArticleToListDetailDO(ArrayObject $listArticle, $numCommande){
		$listDetailDO = new ArrayObject();
		foreach($listArticle as $article){
			$detailDO = new DetailDO();
			$detailDO->setNumeroArticle($article->getNumArticle());
			$detailDO->setNumeroCommande($numCommande);
			$detailDO->setQuantiteCommandee($article->getQuantiteCommandee());

			$listDetailDO->append($detailDO);
		}

		return $listDetailDO;
	}

	private function convertDetailDOtoArticle(DetailDO $detailDO, ArticleDO $articleDO, TypeArticleDO $typeArticleDO){
		$article = new Article();
		$article->setLibelleTypeArticle($typeArticleDO->getLibelle());
		$article->setLibelle($articleDO->getLibelle());
		$article->setNumArticle($articleDO->getNumArticle());
		$article->setPrixUnitaire($articleDO->getPrixUnitaire());
		$article->setQuantiteCommandee($detailDO->getQuantiteCommande());
		$article->setQuantiteDisponible($articleDO->getQuantiteDisponible());

		return $article;
	}

	private function convertLieuDOtoLieu(LieuDO $lieuDO){
		$lieu = new Lieu();
		$lieu->setAdresse($lieuDO->getAdresse());
		$lieu->setNumeroLieu($lieuDO->getNumeroLieu());
		return $lieu;
	}

	private function convertCommandeFactureDOtoCommande(CommandeFactureDO $commandeFactureDO, Lieu $lieu, Utilisateur $client, $listArticle) {
		$facture = new Facture();
		$facture->setDateFacture($commandeFactureDO->getDateFacture());
		$facture->setMontantFacture($commandeFactureDO->getMontantFacture());

		$commande = new Commande ();
		$commande->setClient($client);
		$commande->setDateCommande($commandeFactureDO->getDateCommande());
		$commande->setEstValide($commandeFactureDO->estTerminee());
		$commande->setColisFait($commandeFactureDO->estColisFait());


		$commande->setFacture($facture);
		$commande->setLieuLivraison($lieu);
		$commande->setListArticle($listArticle);
		$commande->setNumeroCommande($commandeFactureDO->getNumeroCommande());

		return $commande;

	}

	private function convertResponsableDOtoUtilisateur(ResponsableDO $responsableDO){
		$utilisateur = new Utilisateur();
		$utilisateur->setNom($responsableDO->getNom());
		$utilisateur->setPrenom($responsableDO->getPrenom());
		$utilisateur->setListLieu($this->getListLieu($responsableDO));
		$utilisateur->setEstResponsable(true);
		$utilisateur->setNumeroResponsable($responsableDO->getNumeroResponsable());

		return $utilisateur;
	}

	private function convertArticleToArticleDO(Article $article){
		$articleDO = new ArticleDO();
		$articleDO->setCodeTypeArticle($article->getLibelleTypeArticle());
		$articleDO->setLibelle($article->getLibelle());
		$articleDO->setNumArticle($article->getNumArticle());
		$articleDO->setPrixUnitaire($article->getPrixUnitaire());
		$articleDO->setQuantiteDisponible($article->getQuantiteDisponible());

		return $articleDO;
	}
}